package com.example.infrastructure.aspect;

import com.example.infrastructure.annotation.OperationLog;
import com.example.infrastructure.persistence.po.UserOperationLog;
import com.example.infrastructure.security.JwtUtils;
import com.example.infrastructure.utils.IpUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;

@Slf4j
@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private JwtUtils jwtUtils;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    @Qualifier("redisObjectMapper")
    private ObjectMapper objectMapper;

    @Around("@annotation(operationLog)")
    public Object around(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {
        long startTime = System.currentTimeMillis();
        UserOperationLog logRecord = new UserOperationLog();
        
        try {
            // 获取请求信息
            HttpServletRequest request = getHttpServletRequest();
            if (request != null) {
                fillRequestInfo(logRecord, request, joinPoint, operationLog);
            }
            
            // 执行方法
            Object result = joinPoint.proceed();
            
            // 记录成功信息
            long executionTime = System.currentTimeMillis() - startTime;
            logRecord.setExecutionTime(executionTime);
            logRecord.setStatus(1);
            
            if (operationLog.recordResult()) {
                logRecord.setResponseResult(objectMapper.writeValueAsString(result));
            }
            
            // 异步保存日志
            saveLogAsync(logRecord);
            
            return result;
            
        } catch (Exception e) {
            // 记录异常信息
            long executionTime = System.currentTimeMillis() - startTime;
            logRecord.setExecutionTime(executionTime);
            logRecord.setStatus(0);
            logRecord.setErrorMsg(e.getMessage());
            
            saveLogAsync(logRecord);
            throw e;
        }
    }
    
    private void fillRequestInfo(UserOperationLog logRecord, HttpServletRequest request, 
                                ProceedingJoinPoint joinPoint, OperationLog operationLog) {
        try {
            // 基本信息
            logRecord.setModule(operationLog.module());
            logRecord.setOperationType(operationLog.type());
            logRecord.setOperationDesc(operationLog.description());
            logRecord.setRequestMethod(request.getMethod());
            logRecord.setRequestUrl(request.getRequestURL().toString());
            logRecord.setIpAddress(IpUtils.getClientIp(request));
            logRecord.setUserAgent(request.getHeader("User-Agent"));
            logRecord.setTraceId(MDC.get("traceId"));
            logRecord.setCreateTime(LocalDateTime.now());
            
            // 用户信息
            String token = getTokenFromRequest(request);
            if (StringUtils.hasText(token)) {
                try {
                    Long userId = jwtUtils.getUserIdFromToken(token);
                    String username = jwtUtils.getUsernameFromToken(token);
                    logRecord.setUserId(userId);
                    logRecord.setUsername(username);
                } catch (Exception e) {
                    log.warn("获取用户信息失败: {}", e.getMessage());
                }
            }
            
            // 请求参数
            if (operationLog.recordParams()) {
                Object[] args = joinPoint.getArgs();
                logRecord.setRequestParams(objectMapper.writeValueAsString(args));
            }
            
        } catch (Exception e) {
            log.error("填充请求信息失败", e);
        }
    }
    
    private void saveLogAsync(UserOperationLog logRecord) {
        // 使用Redis队列异步保存日志
        try {
            redisTemplate.opsForList().leftPush("operation_log_queue", logRecord);
        } catch (Exception e) {
            log.error("保存操作日志失败", e);
        }
    }
    
    private HttpServletRequest getHttpServletRequest() {
        ServletRequestAttributes attributes = 
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes != null ? attributes.getRequest() : null;
    }
    
    private String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}